package org.example.reference;

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;

/**
 * 虚引用测试
 *
 * @author youshang
 * @date 2022/03/31 02:37
 **/
public class PhantomReferenceTest {
    public static PhantomReferenceTest obj; //当前类对象的声明
    static ReferenceQueue<PhantomReferenceTest> phantomQueue = null;//引用队列

    public static class CheckRefQueue extends Thread {
        @Override
        public void run() {
            while (true) {
                if (phantomQueue != null) {
                    PhantomReference<PhantomReferenceTest> objt = null;
                    try {
                        objt = (PhantomReference<PhantomReferenceTest>) phantomQueue.remove();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    if (objt != null) {
                        System.out.println("追踪垃圾回收过程: PhantomReference Test 实例化被GC了");
                    }
                }
            }
        }
    }

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("调用当前类的finalize 方法");
        obj = this;
    }

    public static void main(String[] args) {
        //不可获取虚引用对象
        test1();
        //第一次进行GC，由于对象可复活，GC 无法回收该对象
        test2();
        //在finalize()方法中被复活， 在第二次GC的时候被回收了
        test3();
        //一旦将obj对象回收，就会将此虚引用存放到引用队列之中。
        test4();
    }

    public static void test1(){
        phantomQueue = new ReferenceQueue<>();
        obj = new PhantomReferenceTest();
        //构造了 PhantomReferenceTest 对象的虚引用，并指定了引用队列
        PhantomReference<PhantomReferenceTest> phantomReference = new PhantomReference<>(obj, phantomQueue);
        //不可获取虚引用对象
        System.out.println(phantomReference.get());
    }
    public static void test2(){
        phantomQueue = new ReferenceQueue<>();
        obj = new PhantomReferenceTest();
        //构造了 PhantomReferenceTest 对象的虚引用，并指定了引用队列
        PhantomReference<PhantomReferenceTest> phantomReference = new PhantomReference<>(obj, phantomQueue);
        try {
            //不可获取虚引用对象
            System.out.println(phantomReference.get());
            //将强引用去除
            obj = null;
            //第一次进行GC，由于对象可复活，GC 无法回收该对象
            System.gc();
            Thread.sleep(1000);
            if (obj == null) {
                System.out.println("obj is null");
            } else {
                System.out.println("obj is not null");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static void test3(){
        phantomQueue = new ReferenceQueue<>();
        obj = new PhantomReferenceTest();
        //构造了 PhantomReferenceTest 对象的虚引用，并指定了引用队列
        PhantomReference<PhantomReferenceTest> phantomReference = new PhantomReference<>(obj, phantomQueue);
        try {
            //不可获取虚引用对象
            System.out.println(phantomReference.get());
            //将强引用去除
            obj = null;
            //第一次进行GC，由于对象可复活，GC 无法回收该对象
            System.gc();
            Thread.sleep(1000);
            if (obj == null) {
                System.out.println("obj is null");
            } else {
                System.out.println("obj is not null");
            }

            System.out.println("第二次 GC");
            obj = null;
            System.gc();
            Thread.sleep(1000);
            if (obj == null) {
                System.out.println("obj is null");
            } else {
                System.out.println(" obj is noe null");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static void test4(){
        Thread t = new CheckRefQueue();
        t.setDaemon(true); // 设置守护线程：当程序中没有非守护线程时，守护线程也就执行结束。
        t.start();

        phantomQueue = new ReferenceQueue<>();
        obj = new PhantomReferenceTest();
        //构造了 PhantomReferenceTest 对象的虚引用，并指定了引用队列
        PhantomReference<PhantomReferenceTest> phantomReference = new PhantomReference<>(obj, phantomQueue);
        try {
            //不可获取虚引用对象
            System.out.println(phantomReference.get());
            //将强引用去除
            obj = null;
            //第一次进行GC，由于对象可复活，GC 无法回收该对象
            System.gc();
            Thread.sleep(1000);
            if (obj == null) {
                System.out.println("obj is null");
            } else {
                System.out.println("obj is not null");
            }

            System.out.println("第二次 GC");
            obj = null;
            System.gc(); // 一旦将obj对象回收，就会将此虚引用存放到引用队列之中。
            Thread.sleep(1000);
            if (obj == null) {
                System.out.println("obj is null");
            } else {
                System.out.println(" obj is noe null");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
